package org.ushio.speech_module.speech.dialoguebook;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.ushio.common_module.config.annotation.Loggable;
import org.ushio.common_module.debounce.Debounce;
import org.ushio.common_module.util.response.ResponseResult;
import org.ushio.common_module.util.response.ResultCode;

import java.io.IOException;
import java.time.Duration;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author Asus
 */
@Slf4j
@RestController
@RequestMapping("/api/books")
public class DialogueBookController {

    private static final String CACHE_KEY_PREFIX = "book:";
    private static final String CACHE_KEY_ALL_BOOKS = "page:all_books";
    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
    private static final Duration CACHE_EXPIRATION = Duration.ofMinutes(15);

    @Autowired
    private DialogueBookService dialogueBookService;

    @Autowired
    @Qualifier("speechRedisTemplate")
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 获取指定 ID 的对话本信息
     * @param id 书籍 ID
     * @return ResponseResult<DialogueBookDTO>
     */
    @GetMapping("/{id}")
    public ResponseResult<DialogueBookDTO> getBookById(@PathVariable Long id) {
        try {
            log.info("Fetching book with ID: {}", id);

            // 尝试从 Redis 中获取书籍信息
            String key = CACHE_KEY_PREFIX + id;
            DialogueBookDTO bookDTO = (DialogueBookDTO) redisTemplate.opsForValue().get(key);

            if (bookDTO == null) {
                log.info("Book not found in Redis, fetching from database");
                // 如果 Redis 中没有，从数据库中获取
                DialogueBook book = dialogueBookService.getBookById(id);
                if (book == null) {
                    log.warn("Book with ID {} not found in the database", id);
                    return ResponseResult.failed(ResultCode.NOT_FOUND.getCode(), "书籍不存在");
                }

                // 转换为 DTO 并存储到 Redis
                bookDTO = new DialogueBookDTO(book.getBookId(), book.getTitle(), book.getDescription(), book.getPicture());
                redisTemplate.opsForValue().set(key, bookDTO);
            }

            return ResponseResult.success(bookDTO);
        } catch (Exception e) {
            log.error("Error while fetching book with ID: {}", id, e);
            return ResponseResult.failed(ResultCode.INTERNAL_ERROR.getCode(), "内部服务器错误");
        }
    }

    /**
     * 获取全部对话本信息
     * @return ResponseResult<List<DialogueBookDTO>>
     */
    @GetMapping
    public ResponseResult<List<DialogueBookDTO>> getAllBooks() {
        try {
            log.info("Fetching all books");

            // 尝试从 Redis 中获取缓存的页面内容
            String cachedPage = (String) redisTemplate.opsForValue().get(CACHE_KEY_ALL_BOOKS);
            if (cachedPage != null) {
                log.info("Returning cached page for all books");
                List<DialogueBookDTO> bookDTOs = OBJECT_MAPPER.readValue(cachedPage, OBJECT_MAPPER.getTypeFactory().constructCollectionType(List.class, DialogueBookDTO.class));
                return ResponseResult.success(bookDTOs);
            }

            // 如果 Redis 中没有缓存，从数据库中获取
            log.info("Fetching all books from database");
            List<DialogueBookDTO> bookDTOs = dialogueBookService.getAllBooks()
                    .stream()
                    .map(b -> new DialogueBookDTO(b.getBookId(), b.getTitle(), b.getDescription(), b.getPicture()))
                    .collect(Collectors.toList());

            // 将结果转换为 JSON 并存储到 Redis
            String jsonResponse = OBJECT_MAPPER.writeValueAsString(bookDTOs);
            redisTemplate.opsForValue().set(CACHE_KEY_ALL_BOOKS, jsonResponse, CACHE_EXPIRATION);

            return ResponseResult.success(bookDTOs);
        } catch (Exception e) {
            log.error("Error while fetching all books", e);
            return ResponseResult.failed(ResultCode.INTERNAL_ERROR.getCode(), "内部服务器错误");
        }
    }

    /**
     * 添加新对话本
     * @param uploadDTO 上传的对话本信息
     *                   包含书籍标题、描述、图片
     * @return ResponseResult<Void>
     */
    @PostMapping
    @Debounce(interval = 500)
    @Loggable("新增对话本")
    public ResponseResult<Void> addDialogueBook(@ModelAttribute DialogueBookUploadDTO uploadDTO) {
        try {
            log.info("Adding new dialogue book: {}", uploadDTO.getTitle());

            // 调用服务层保存书籍信息
            dialogueBookService.addDialogueBook(uploadDTO);

            // 清除全部书籍列表缓存
            redisTemplate.delete(CACHE_KEY_ALL_BOOKS);

            return ResponseResult.success();
        } catch (IOException e) {
            log.error("Error processing uploaded image for book: {}", uploadDTO.getTitle(), e);
            return ResponseResult.failed(ResultCode.INTERNAL_ERROR.getCode(), "图片处理失败");
        } catch (Exception e) {
            log.error("Error while adding dialogue book", e);
            return ResponseResult.failed(ResultCode.INTERNAL_ERROR.getCode(), "添加书籍失败");
        }
    }

    /**
     * 修改对话本信息
     * @param id 书籍 ID
     * @param uploadDTO 上传的对话本信息
     *                   包含书籍标题、描述、图片
     * @return ResponseResult<Void>
     */
    @Loggable("修改对话本")
    @PutMapping("/{id}")
    @Debounce(interval = 500)
    public ResponseResult<Void> updateDialogueBook(@PathVariable Long id, @ModelAttribute DialogueBookUploadDTO uploadDTO) {
        try {
            log.info("Updating dialogue book with ID: {}", id);
            dialogueBookService.updateDialogueBook(id, uploadDTO);

            // 清除对应的单个书籍缓存和全部书籍列表缓存
            String key = CACHE_KEY_PREFIX + id;
            redisTemplate.delete(key);
            redisTemplate.delete(CACHE_KEY_ALL_BOOKS);

            return ResponseResult.success();
        } catch (IOException e) {
            log.error("Error processing uploaded image for book: {}", id, e);
            return ResponseResult.failed(ResultCode.INTERNAL_ERROR.getCode(), "图片处理失败");
        } catch (Exception e) {
            log.error("Error while updating dialogue book with ID: {}", id, e);
            return ResponseResult.failed(ResultCode.INTERNAL_ERROR.getCode(), "更新书籍失败");
        }
    }

    /**
     * 删除对话本信息
     * @param id 书籍 ID
     *            要删除的书籍 ID
     * @return ResponseResult<Void>
     */
    @Loggable("删除对话本")
    @DeleteMapping("/{id}")
    @Debounce(interval = 500)
    public ResponseResult<Void> deleteDialogueBook(@PathVariable Long id) {
        try {
            log.info("Deleting dialogue book with ID: {}", id);
            dialogueBookService.deleteDialogueBook(id);

            // 清除对应的单个书籍缓存和全部书籍列表缓存
            String key = CACHE_KEY_PREFIX + id;
            redisTemplate.delete(key);
            redisTemplate.delete(CACHE_KEY_ALL_BOOKS);

            return ResponseResult.success();
        } catch (RuntimeException e) {
            log.error("Error while deleting dialogue book with ID: {}", id, e);
            return ResponseResult.failed(ResultCode.INTERNAL_ERROR.getCode(), e.getMessage());
        } catch (Exception e) {
            log.error("Error while deleting dialogue book with ID: {}", id, e);
            return ResponseResult.failed(ResultCode.INTERNAL_ERROR.getCode(), "删除书籍失败");
        }
    }
}